package sd

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/shirou/gopsutil/cpu"
	"github.com/shirou/gopsutil/disk"
	"github.com/shirou/gopsutil/host"
	"github.com/shirou/gopsutil/load"
	"github.com/shirou/gopsutil/mem"
	"github.com/shirou/gopsutil/net"
	"go-papers/tools/app"
	"net/http"
	"runtime"
	"time"
)

const (
	B  = 1
	KB = 1024 * B
	MB = 1024 * KB
	GB = 1024 * MB
)

func Info(c *gin.Context) {
	ret := make(map[string]interface{})

	ho, _ := host.Info()
	ret["host_info"] = ho
	ret["host_info_name"] = "本机信息"

	co, _ := cpu.Info() //总体信息
	ret["cpu_info"] = co
	ret["cpu_info_name"] = "cpu总体信息"

	cc, _ := cpu.Counts(true) //cpu逻辑数量
	ret["cpu_cc"] = cc
	ret["cpu_cc_name"] = "cpu逻辑数量"

	cs, _ := cpu.Counts(false) //cpu物理核心
	//如果是2说明是双核超线程, 如果是4则是4核非超线程
	ret["cpu_cs"] = cs
	ret["cpu_cs_name"] = "cpu物理核心"

	//用户CPU时间：就是用户的进程获得了CPU资源以后，在用户态执行的时间。
	//系统CPU时间：用户进程获得了CPU资源以后，在内核态的执行时间。
	i, _ := cpu.Times(false)
	ret["cpu_time"] = i
	ret["cpu_time_name"] = "CPU时间"

	//获取当前网络连接信息
	info, _ := net.Connections("all") //可填入tcp、udp、tcp4、udp4等等
	ret["net"] = info
	ret["net_name"] = "网络连接信息"

	//可以通过psutil获取磁盘分区、磁盘使用率和磁盘IO信息：
	dis, _ := disk.Partitions(true) //所有分区
	ret["disk"] = dis
	ret["disk_name"] = "磁盘分区"

	//所有硬盘的io信息
	info3, _ := disk.IOCounters()
	ret["disk_io"] = info3
	ret["disk_io_name"] = "网络连接信息"

	u, _ := disk.Usage("/")

	usedMB := int(u.Used) / MB
	usedGB := int(u.Used) / GB
	totalMB := int(u.Total) / MB
	totalGB := int(u.Total) / GB
	usedPercent := int(u.UsedPercent)

	ret["disk_info"] = fmt.Sprintf("Free space: %dMB (%dGB) / %dMB (%dGB) | Used: %d%%", usedMB, usedGB, totalMB, totalGB, usedPercent)

	app.OK(c, ret, "OK")
}

// 健康状况
// @Summary 健康状况 HealthCheck shows OK as the ping-pong result.
// @Description 健康状况
// @Accept text/html
// @Produce text/html
// @Success 200 {string} string "OK"
// @Router /sd/health [get]
// @BasePath
func HealthCheck(c *gin.Context) {
	app.OK(c, "", "OK")
}

// @Summary 服务器硬盘使用量
// @Description 服务器硬盘使用量 DiskCheck checks the disk usage.
// @Accept  text/html
// @Produce text/html
// @Success 200 {string} string "OK - Free space: 16321MB (15GB) / 51200MB (50GB) | Used: 31%"
// @Failure 500 {string} string "CRITICAL"
// @Failure 429 {string} string "WARNING"
// @Router /sd/disk [get]
// @BasePath
func DiskCheck(c *gin.Context) {
	u, _ := disk.Usage("/")

	usedMB := int(u.Used) / MB
	usedGB := int(u.Used) / GB
	totalMB := int(u.Total) / MB
	totalGB := int(u.Total) / GB
	usedPercent := int(u.UsedPercent)

	status := http.StatusOK
	text := "OK"

	if usedPercent >= 95 {
		status = http.StatusOK
		text = "CRITICAL"
	} else if usedPercent >= 90 {
		status = http.StatusTooManyRequests
		text = "WARNING"
	}

	message := fmt.Sprintf("%s - Free space: %dMB (%dGB) / %dMB (%dGB) | Used: %d%%", text, usedMB, usedGB, totalMB, totalGB, usedPercent)
	c.String(status, "\n"+message)
}

// @Summary OS
// @Description Os
// @Accept  text/html
// @Produce text/html
// @Success 200 {string} string ""
// @Router /sd/os [get]
// @BasePath
func OSCheck(c *gin.Context) {
	status := http.StatusOK
	app.Custum(c, gin.H{
		"code":    200,
		"message": "success",
		"data": map[string]interface{}{
			"status":       status,
			"goOs":         runtime.GOOS,
			"compiler":     runtime.Compiler,
			"numCpu":       runtime.NumCPU(),
			"version":      runtime.Version(),
			"numGoroutine": runtime.NumGoroutine(),
		},
	})
}

// @Summary CPU 使用量
// @Description CPU 使用量 DiskCheck checks the disk usage.
// @Accept  text/html
// @Produce text/html
// @Success 200 {string} string ""
// @Router /sd/cpu [get]
// @BasePath
func CPUCheck(c *gin.Context) {
	cores, _ := cpu.Counts(false)

	cpus, err := cpu.Percent(time.Duration(200)*time.Millisecond, true)
	if err == nil {
		for i, c := range cpus {
			fmt.Printf("cpu%d : %f%%\n", i, c)
		}
	}

	a, _ := load.Avg()
	l1 := a.Load1
	l5 := a.Load5
	l15 := a.Load15

	status := http.StatusOK
	text := "OK"

	if l5 >= float64(cores-1) {
		status = http.StatusInternalServerError
		text = "CRITICAL"
	} else if l5 >= float64(cores-2) {
		status = http.StatusTooManyRequests
		text = "WARNING"
	}
	app.Custum(c, gin.H{
		"code":    0,
		"message": text,
		"data": map[string]interface{}{
			"status": status,
			"cores":  cores,
			"load1":  l1,
			"load5":  l5,
			"load15": l15,
		},
	})
}

// @Summary 内存使用量
// @Description 内存使用量 RAMCheck checks the disk usage.
// @Accept  text/html
// @Produce text/html
// @Success 200 {string} string ""
// @Router /sd/ram [get]
// @BasePath
func RAMCheck(c *gin.Context) {
	u, _ := mem.VirtualMemory()

	usedMB := int(u.Used) / MB
	totalMB := int(u.Total) / MB
	usedPercent := int(u.UsedPercent)

	status := http.StatusOK
	text := "OK"

	if usedPercent >= 95 {
		status = http.StatusInternalServerError
		text = "CRITICAL"
	} else if usedPercent >= 90 {
		status = http.StatusTooManyRequests
		text = "WARNING"
	}

	app.Custum(c, gin.H{
		"code":    0,
		"message": text,
		"data": map[string]interface{}{
			"status":      status,
			"used":        usedMB,
			"total":       totalMB,
			"usedPercent": usedPercent,
		},
	})
}
